package cn.jbolt.core.bean;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.jbolt.core.util.JBoltDateUtil;
import com.alibaba.fastjson.annotation.JSONField;
import com.jfinal.kit.StrKit;

import java.sql.Time;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

/**
 * 时间日期区间
 *
 * @ClassName: JBoltDateRange
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2022年2月25日
 */
public class JBoltDateRange {
    public static final String TYPE_YEAR = "year";
    public static final String TYPE_MONTH = "month";
    public static final String TYPE_DATE = "date";
    public static final String TYPE_DATETIME = "datetime";
    public static final String TYPE_TIME = "time";
    public static final String DEFAULT_PARA_NAME = "dateRange";
    /**
     * 请求参数名
     */
    private String paraName;
    /**
     * 原解析前数据
     */
    private String originDateRange;
    /**
     * 开始范围值
     */
    private String start;
    /**
     * 结束范围值
     */
    private String end;
    /**
     * 分隔符
     */
    private String splitChar;
    /**
     * 类型 datetime date time month week
     */
    private String type;
    /**
     * 格式
     */
    private String format;

    public JBoltDateRange(String dateRange) {
        this(dateRange, null);
    }

    private String processType() {
        if (start == null || start.trim().length() == 0) {
            return TYPE_DATE;
        }
        if (start.contains("-")) {
            if (start.contains(":")) {
                return TYPE_DATETIME;
            }
            int count = StrUtil.count(start, "-");
            if (count == 1) {
                return TYPE_MONTH;
            }
            return TYPE_DATE;
        } else if (start.contains(":")) {
            return TYPE_TIME;
        } else {
            if (start.length() <= 4) {
                return TYPE_YEAR;
            }
            DateTime startTime = DateUtil.date(Long.parseLong(start));
            DateTime endTime = DateUtil.date(Long.parseLong(end));
            this.start = startTime.toString("yyyy-MM-dd HH:mm:ss");
            this.end = endTime.toString("yyyy-MM-dd HH:mm:ss");
            return processType();
        }
    }

    public JBoltDateRange(String dateRange, String type) {
        this(DEFAULT_PARA_NAME, dateRange, type, "~");
    }

    public JBoltDateRange(String paraName, String dateRange, String type) {
        this(paraName, dateRange, type, "~");
    }

    public JBoltDateRange(String paraName, String dateRange, String type, String splitChar) {
        if (dateRange != null && dateRange.trim().length() > 0) {
            if (dateRange.contains(" 00:00:00")) {
                dateRange = StrUtil.replace(dateRange, " 00:00:00", "");
            } else if (dateRange.contains(" 00:00")) {
                dateRange = StrUtil.replace(dateRange, " 00:00", "");
            }
        }
        List<String> list = StrUtil.splitTrim(dateRange, splitChar);
        if (list != null && list.size() == 2) {
            this.start = list.get(0);
            this.end = list.get(1);
        }
        this.splitChar = splitChar;

        if (type == null || type.trim().length() == 0) {
            this.type = processType();
        } else {
            this.type = type;
        }
        processFormat();
        this.paraName = paraName;
        this.originDateRange = dateRange;
    }

    private void processFormat() {
        switch (type) {
            case TYPE_DATE:
                this.format = JBoltDateUtil.YMD;
                break;
            case TYPE_DATETIME:
                this.format = JBoltDateUtil.YMDHMS;
                break;
            case TYPE_MONTH:
                this.format = JBoltDateUtil.YM;
                break;
            case TYPE_YEAR:
                this.format = JBoltDateUtil.Y;
                break;
            case TYPE_TIME:
                this.format = JBoltDateUtil.HMS;
                break;
        }
    }

    public String getStart() {
        return start;
    }

    public void setStart(String start) {
        this.start = start;
    }

    public String getEnd() {
        return end;
    }

    public void setEnd(String end) {
        this.end = end;
    }

    public String getFormat() {
        return format;
    }

    public void setFormat(String format) {
        this.format = format;
    }

    public String getSplitChar() {
        return splitChar;
    }

    public void setSplitChar(String splitChar) {
        this.splitChar = splitChar;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @JSONField(serialize = false)
    public int getStartYear() {
        if (StrUtil.isBlankIfStr(start)) {
            return 1970;
        }
        start = normalize(start);
        return Integer.parseInt(start.trim());
    }

    @JSONField(serialize = false)
    public int getEndYear() {
        if (StrUtil.isBlankIfStr(end)) {
            return 1970;
        }
        end = normalize(end);
        return Integer.parseInt(end.trim());
    }

    @JSONField(serialize = false)
    public String getStartYearMonth() {
        return normalize(start);
    }

    @JSONField(serialize = false)
    public String getEndYearMonth() {
        return normalize(end);
    }

    @JSONField(serialize = false)
    public Date getStartDate() {
        return start == null ? null : DateUtil.parseDate(start);
    }

    @JSONField(serialize = false)
    public Date getStartDate(Date defaultValue) {
        return start == null ? defaultValue : DateUtil.parseDate(start);
    }

    @JSONField(serialize = false)
    public Date getEndDate() {
        return end == null ? null : DateUtil.parseDate(end);
    }

    @JSONField(serialize = false)
    public Date getEndDate(Date defaultValue) {
        return end == null ? defaultValue : DateUtil.parseDate(end);
    }

    @JSONField(serialize = false)
    public String getStartDateStr() {
        return start == null ? null : DateUtil.parseDate(start).toDateStr();
    }

    @JSONField(serialize = false)
    public String getStartDateStr(String defaultValue) {
        return start == null ? defaultValue : DateUtil.parseDate(start).toDateStr();
    }

    @JSONField(serialize = false)
    public String getEndDateStr() {
        return end == null ? null : DateUtil.parseDate(end).toDateStr();
    }

    @JSONField(serialize = false)
    public String getEndDateStr(String defaultValue) {
        return end == null ? defaultValue : DateUtil.parseDate(end).toDateStr();
    }

    @JSONField(serialize = false)
    public Date getStartDateTime() {
        return start == null ? null : DateUtil.parseDateTime(start);
    }

    @JSONField(serialize = false)
    public Date getStartDateTime(Date defaultValue) {
        return start == null ? defaultValue : DateUtil.parseDateTime(start);
    }

    @JSONField(serialize = false)
    public Date getEndDateTime() {
        return end == null ? null : DateUtil.parseDateTime(end);
    }

    @JSONField(serialize = false)
    public Date getEndDateTime(Date defaultValue) {
        return end == null ? defaultValue : DateUtil.parseDateTime(end);
    }

    @JSONField(serialize = false)
    public String getStartDateTimeStr() {
        return start != null ? DateUtil.parseDateTime(start).toDateStr() : null;
    }

    @JSONField(serialize = false)
    public String getStartDateTimeStr(String defaultValue) {
        return start == null ? defaultValue : DateUtil.parseDateTime(start).toDateStr();
    }

    @JSONField(serialize = false)
    public String getEndDateTimeStr() {
        return end == null ? null : DateUtil.parseDateTime(end).toDateStr();
    }

    @JSONField(serialize = false)
    public String getEndDateTimeStr(String defaultValue) {
        return end == null ? defaultValue : DateUtil.parseDateTime(end).toDateStr();
    }

    @JSONField(serialize = false)
    public Timestamp getStartTimestamp() {
        return start == null ? null : DateUtil.parseTime(start).toTimestamp();
    }

    @JSONField(serialize = false)
    public Timestamp getStartTimestamp(Timestamp defaultValue) {
        return start == null ? defaultValue : DateUtil.parseTime(start).toTimestamp();
    }

    @JSONField(serialize = false)
    public Timestamp getEndTimestamp() {
        return end == null ? null : DateUtil.parseTime(end).toTimestamp();
    }

    @JSONField(serialize = false)
    public Timestamp getEndTimestamp(Timestamp defaultValue) {
        return end == null ? defaultValue : DateUtil.parseTime(end).toTimestamp();
    }

    @JSONField(serialize = false)
    public Time getStartTime() {
        return start == null ? null : JBoltDateUtil.getTime(start);
    }

    @JSONField(serialize = false)
    public Time getEndTime() {
        return start == null ? null : JBoltDateUtil.getTime(end);
    }

    @JSONField(serialize = false)
    public String getStartTimeStr() {
        if (StrKit.notBlank(start)) {
            if (start.trim().split(":").length != 3) {
                start = start + ":00";
            }
        }
        return start == null ? null : DateUtil.parseTime(start).toTimeStr();
    }

    @JSONField(serialize = false)
    public String getStartTimeStr(String defaultValue) {
        if (StrKit.notBlank(start)) {
            if (start.trim().split(":").length != 3) {
                start = start + ":00";
            }
        }
        return start == null ? defaultValue : DateUtil.parseTime(start).toTimeStr();
    }

    @JSONField(serialize = false)
    public String getEndTimeStr() {
        if (StrKit.notBlank(end)) {
            if (end.trim().split(":").length != 3) {
                end = end + ":00";
            }
        }
        return end == null ? null : DateUtil.parseTime(end).toTimeStr();
    }

    @JSONField(serialize = false)
    public String getEndTimeStr(String defaultValue) {
        if (StrKit.notBlank(end)) {
            if (end.trim().split(":").length != 3) {
                end = end + ":00";
            }
        }
        return end == null ? defaultValue : DateUtil.parseTime(end).toTimeStr();
    }

    private String normalize(String dateStr) {
        if (StrUtil.isBlank(dateStr)) {
            return StrUtil.str(dateStr);
        }

        // 日期时间分开处理
        final List<String> dateAndTime = StrUtil.splitTrim(dateStr, ' ');
        final int size = dateAndTime.size();
        if (size < 1 || size > 2) {
            // 非可被标准处理的格式
            return StrUtil.str(dateStr);
        }

        final StringBuilder builder = StrUtil.builder();

        // 日期部分（"\"、"/"、"."、"年"、"月"都替换为"-"）
        String datePart = dateAndTime.get(0).replaceAll("[/.年月]", "-");
        datePart = StrUtil.removeSuffix(datePart, "日");
        builder.append(datePart);

        // 时间部分
        if (size == 2) {
            builder.append(' ');
            String timePart = dateAndTime.get(1).replaceAll("[时分秒]", ":");
            timePart = StrUtil.removeSuffix(timePart, ":");
            // 将ISO8601中的逗号替换为.
            timePart = timePart.replace(',', '.');
            builder.append(timePart);
        }

        return builder.toString();
    }

    public String getOriginDateRange() {
        return originDateRange;
    }

    public void setOriginDateRange(String originDateRange) {
        this.originDateRange = originDateRange;
    }

    public String getParaName() {
        return paraName;
    }

    public void setParaName(String paraName) {
        this.paraName = paraName;
    }

    @JSONField(serialize = false)
    public boolean isEmpty() {
        return StrKit.isBlank(getOriginDateRange());
    }
}
